/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_orm.htm
 *
 * Zhiqim Orm is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.orm;

import java.util.Map;

import org.zhiqim.kernel.Global;
import org.zhiqim.kernel.Servicer;
import org.zhiqim.kernel.extend.HashMapCV;
import org.zhiqim.kernel.extend.HashMapSO;
import org.zhiqim.kernel.extend.HashMapSS;
import org.zhiqim.kernel.extend.LinkedMapSO;
import org.zhiqim.kernel.extend.MapSO;
import org.zhiqim.kernel.extend.TreeMapSO;
import org.zhiqim.kernel.schedule.TaskThreader;
import org.zhiqim.kernel.util.Types;
import org.zhiqim.orm.annotation.AnDbo;
import org.zhiqim.orm.annotation.AnTable;
import org.zhiqim.orm.annotation.AnView;
import org.zhiqim.orm.dbo.Dbo;
import org.zhiqim.orm.executor.BatchExecutor;
import org.zhiqim.orm.executor.BatchExecutorBase;
import org.zhiqim.orm.executor.BatchExecutorClass;
import org.zhiqim.orm.executor.BatchExecutorMap;
import org.zhiqim.orm.executor.CallExecutor;
import org.zhiqim.orm.executor.QueryExecutor;
import org.zhiqim.orm.executor.QueryExecutorBaseBase;
import org.zhiqim.orm.executor.QueryExecutorBaseClass;
import org.zhiqim.orm.executor.QueryExecutorBaseMap;
import org.zhiqim.orm.executor.QueryExecutorClassBase;
import org.zhiqim.orm.executor.QueryExecutorClassClass;
import org.zhiqim.orm.executor.QueryExecutorClassMap;
import org.zhiqim.orm.executor.QueryExecutorMapBase;
import org.zhiqim.orm.executor.QueryExecutorMapClass;
import org.zhiqim.orm.executor.QueryExecutorMapMap;
import org.zhiqim.orm.executor.UpdateExecutor;
import org.zhiqim.orm.executor.UpdateExecutorBase;
import org.zhiqim.orm.executor.UpdateExecutorClass;
import org.zhiqim.orm.executor.UpdateExecutorMap;
import org.zhiqim.orm.impl.ZDDLImplement;
import org.zhiqim.orm.impl.ZSQLImplement;
import org.zhiqim.orm.impl.ZTableImplement;
import org.zhiqim.orm.impl.ZTablerImplement;
import org.zhiqim.orm.impl.ZViewImplement;

/**
 * ORM预处理，从ORMServer中独立出来一个抽象类，这样ORMServer就不会太大，易管理
 *
 * @version v1.0.0 @author zouzhigang 2018-11-26 新建与整理
 */
public abstract class ORMPredefinded extends Servicer
{
    //SQL处理器
    protected final HashMapCV<CallExecutor> callMap = new HashMapCV<>();
    protected final HashMapCV<UpdateExecutor> updateMap = new HashMapCV<>();
    protected final HashMapCV<BatchExecutor> batchMap = new HashMapCV<>();
    protected final HashMapCV<QueryExecutor> queryMap = new HashMapCV<>();
    
    //SQL表和缓存表
    protected final HashMapSS sqlMap = new HashMapSS();
    protected final HashMapCV<TaskThreader> cacheMap = new HashMapCV<>();
    
    //ORM指令对象
    protected ZSQLImplement zSQL;
    protected ZDDLImplement zDDL;
    protected ZTableImplement zTable;
    protected ZTablerImplement zTabler;
    protected ZViewImplement zView;
    
    /***********************************************************************************/
    //ORM预开启&关闭
    /***********************************************************************************/
    
    /** 开启 */
    protected void open()
    {
      //call
        callMap.put(CallExecutor.class, new CallExecutor());
        //update
        updateMap.put(UpdateExecutorBase.class, new UpdateExecutorBase());
        updateMap.put(UpdateExecutorClass.class, new UpdateExecutorClass());
        updateMap.put(UpdateExecutorMap.class, new UpdateExecutorMap());
        //batch
        batchMap.put(BatchExecutorBase.class, new BatchExecutorBase());
        batchMap.put(BatchExecutorClass.class, new BatchExecutorClass());
        batchMap.put(BatchExecutorMap.class, new BatchExecutorMap());
        //query
        queryMap.put(QueryExecutorBaseBase.class, new QueryExecutorBaseBase());
        queryMap.put(QueryExecutorBaseClass.class, new QueryExecutorBaseClass());
        queryMap.put(QueryExecutorBaseMap.class, new QueryExecutorBaseMap());
        queryMap.put(QueryExecutorClassBase.class, new QueryExecutorClassBase());
        queryMap.put(QueryExecutorClassClass.class, new QueryExecutorClassClass());
        queryMap.put(QueryExecutorClassMap.class, new QueryExecutorClassMap());
        queryMap.put(QueryExecutorMapBase.class, new QueryExecutorMapBase());
        queryMap.put(QueryExecutorMapClass.class, new QueryExecutorMapClass());
        queryMap.put(QueryExecutorMapMap.class, new QueryExecutorMapMap());
    }
    
    /** 关闭 */
    protected void close()
    {
        sqlMap.clear();
        updateMap.clear();
        batchMap.clear();
        queryMap.clear();
    }
    
    /***********************************************************************************/
    //获取ORM指令对象，目前共5个（sql,ddl,table,tabler,view）
    /***********************************************************************************/
    
    public ZSQL sql()
    {
        return zSQL;
    }
    
    public ZDDL ddl()
    {
        return zDDL;
    }
    
    public ZTable table()
    {
        return zTable;
    }
    
    public ZView view()
    {
        return zView;
    }
    
    public ZTabler tabler()
    {
        return zTabler;
    }
    
    /***********************************************************************************/
    //获取ORM指令对象，目前共5个（sql,ddl,table,tabler,view）
    /***********************************************************************************/

    public String getSQL(String id)
    {
        return sqlMap.get(id);
    }
    
    public CallExecutor getCallExecutor()
    {
        return callMap.get(CallExecutor.class);
    }
    
    public UpdateExecutor getUpdateExecutor(Class<?> clazz)
    {
        return updateMap.get(clazz);
    }
    
    public UpdateExecutor getUpdateExecutor(Object param)
    {
        if (isParamBase(param))
        {//基本类型和数组
            return updateMap.get(UpdateExecutorBase.class);
        }
        else if (param instanceof Map<?, ?> || param instanceof MapSO)
        {//MAP
            return updateMap.get(UpdateExecutorMap.class);
        }
        else if (this.isDbo(param.getClass()))
        {//DBO
            return updateMap.get(UpdateExecutorClass.class);
        }
        else
        {//其他的不支持
            return null;
        }
    }
    
    public BatchExecutor getBatchExecutor(Object param)
    {
        if (isParamBase(param))
        {//基本类型和数组
            return batchMap.get(BatchExecutorBase.class);
        }
        else if (param instanceof Map<?, ?> || param instanceof MapSO)
        {//MAP
            return batchMap.get(BatchExecutorMap.class);
        }
        else if (this.isDbo(param.getClass()))
        {//DBO
            return batchMap.get(BatchExecutorClass.class);
        }
        else
        {//其他的不支持
            return null;
        }
    }
    
    public QueryExecutor getQueryExecutor(Object param, Class<?> resultClass) 
    {
        if (isParamBase(param))
        {//基础类型
            if (isResultBase(resultClass))
                return queryMap.get(QueryExecutorBaseBase.class);
            
            if (resultClass == Map.class || resultClass == MapSO.class || resultClass == HashMapSO.class || resultClass == LinkedMapSO.class || resultClass == TreeMapSO.class)
                return queryMap.get(QueryExecutorBaseMap.class);
            
            if (isDbo(resultClass))
                return queryMap.get(QueryExecutorBaseClass.class);
            
            return null;
        }
        
        if (param instanceof Map<?, ?> || param instanceof MapSO)
        {//MAP
            if (isResultBase(resultClass))
                return queryMap.get(QueryExecutorMapBase.class);
            
            if (resultClass == Map.class || resultClass == MapSO.class || resultClass == HashMapSO.class || resultClass == LinkedMapSO.class || resultClass == TreeMapSO.class)
                return queryMap.get(QueryExecutorMapMap.class);
            
            if (isDbo(resultClass))
                return queryMap.get(QueryExecutorMapClass.class);
            
            return null;
        }
        
        if (isDbo(param.getClass()))
        {//DBO
            if (isResultBase(resultClass))
                return queryMap.get(QueryExecutorClassBase.class);
            
            if (resultClass == Map.class || resultClass == MapSO.class || resultClass == HashMapSO.class || resultClass == LinkedMapSO.class || resultClass == TreeMapSO.class)
                return queryMap.get(QueryExecutorClassMap.class);
            
            if (isDbo(resultClass))
                return queryMap.get(QueryExecutorClassClass.class);
            
            return null;
        }
        
        return null;
    }
    
    public BatchExecutor getBatchExecutor(Class<?> clazz)
    {
        return batchMap.get(clazz);
    }
    
    public QueryExecutor getQueryExecutor(Class<?> clazz)
    {
        return queryMap.get(clazz);
    }
    
    public boolean isParamBase(Object param)
    {
        return (param == null || param instanceof Integer || param instanceof Long || param instanceof String || Types.isArray(param));
    }
    
    public boolean isResultBase(Class<?> resultClass)
    {
        return resultClass == int.class || resultClass == Integer.class || resultClass == long.class || resultClass == Long.class || resultClass == String.class;
    }
    
    public boolean isDbo(String name)
    {
        return isDbo(Global.forName(name));
    }
    
    public boolean isDbo(Class<?> clazz)
    {
        if (clazz == null)
            return false;
        else if (clazz.isAnnotationPresent(AnTable.class))
            return true;
        else if (clazz.isAnnotationPresent(AnView.class))
            return true;
        else if (clazz.isAnnotationPresent(AnDbo.class))
            return true;
        else
            return false;
    }
    
    public Dbo getDbo(String name)
    {
        Class<?> clazz = Global.forName(name);
        if (clazz == null)
            return null;
        else
            return getDbo(clazz);
    }
    
    public Dbo getDbo(Class<?> clazz)
    {
        if (clazz.isAnnotationPresent(AnTable.class))
            return zTable.getTable(clazz);
        else if (clazz.isAnnotationPresent(AnView.class))
            return zView.getView(clazz);
        else if (clazz.isAnnotationPresent(AnDbo.class))
            return zSQL.getDbo(clazz);
        else
            return null;
    }
}
